﻿using System;
using System.Collections;
using System.Collections.Generic;
using LiveLinq.Internal;

namespace LiveLinq
{
	public static class ObservableEnumerable
	{
		/// <summary>
		/// Safe downcast, like collections convariance
		/// </summary>
		/// <param name="source"></param>
		/// <returns></returns>
		public static IEnumerable<TResult> Cast<TResult, TSource>(IEnumerable<TSource> source) where TSource : TResult
		{
			throw new NotImplementedException();
			// return null; // new ObservableSafeDownCast<TResult, TSource>(source);
		}

		/// <summary>
		/// Cast all elements to another type
		/// </summary>
		/// <param name="source"></param>
		/// <returns></returns>
		public static IEnumerable<TResult> Cast<TResult>(IEnumerable source)
		{
			// TODO detect for safe downcast
			// TODO in case of safe downcast in Net4.0 trace warning about co-variance
			throw new NotImplementedException();
		}

		public static IEnumerable<T> Where<T>(this IEnumerable<T> source, Func<T, bool> predicate)
		{
			return new WhereQueryResult<T>(source, predicate);
		}

        public static IEnumerable<T> Where<T>(this IEnumerable<T> source, Func<T, int, bool> predicate)
        {
            return new WhereQueryResultWithIndex<T>(source, predicate);
        }

		/*
		public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, IValueProvider<bool>> predicate);
		public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);
		public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, int, IValueProvider<bool>> predicate);
		*/

		public static IValueProvider<bool> Any<T>(this IEnumerable<T> source, Func<T, bool> predicate)
		{
			return new AnyQueryResult<T>(source, predicate);
		}

		public static IValueProvider<bool> Any<T>(this IEnumerable<T> source)
		{
			// return new AnyQueryResult<T>(source, x => true);
			return new AnyExistQueryResult<T>(source);
		}

		public static IEnumerable<T> Empty<T>()
		{
			return EmptyEnumerable<T>.Instance;
		}
		
		public static IValueProvider<T> First<T>(this IEnumerable<T> source)
		{
			return new FirstQueryResult<T>(source);
		}
		
		public static IValueProvider<T> First<T>(this IEnumerable<T> source, Func<T, bool> predicate)
		{
			return new FirstQueryResultWithPredicate<T>(source, predicate);
		}

		/// <summary>
		/// from System.Linq
		/// </summary>
		/// <typeparam name="TElement"></typeparam>
		public static IValueProvider<bool> All<T>(this IEnumerable<T> source, Func<T, bool> predicate)
		{
			return new AllQueryResult<T>(source, predicate);
		}

		public static IEnumerable<T> Concat<T>(this IEnumerable<T> first, IEnumerable<T> second)
		{
			return new ConcatQueryResult<T>(first, second);
		}
	}
}